﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Core.DeviceProtocol;
using Core.Model;
using Core.Msg;
using log4net;

namespace Core.ChannelProtocol
{
    /// <summary>
    /// 通道协议基类型
    /// </summary>
    public abstract class BaseChannel : IChannel
    {

        #region IChannel 成员
        private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        public BaseDevProtocol CurDevProtocol { get;protected set; }
        public event EventHandler OnNewMessage;
        protected readonly Dictionary<string, BaseDevProtocol> protocols = new Dictionary<string, BaseDevProtocol>();
        protected virtual void LoadProtocol(Device device)
        {
            try
            {
                if (device != null && !string.IsNullOrEmpty(device.Protocol))
                {
                    string strPath = Global.DataAccess.GetDevProtocolPath();
                    DirectoryInfo driverPath = new DirectoryInfo(strPath);
                    FileInfo[] files = driverPath.GetFiles();

                    for (int i = 0; i < files.Length; i++)
                    {
                        FileVersionInfo info = FileVersionInfo.GetVersionInfo(files[i].FullName);
                        if (info.ProductName != device.Protocol) continue;
                        if (files[i].Name.Contains(".dll") || files[i].Name.Contains(".DLL"))
                        {
                            string proPath = Path.Combine(strPath, files[i].Name);
                            Assembly asm = Assembly.Load(new AssemblyName() { CodeBase = proPath });
                            foreach (Type extype in asm.GetExportedTypes())
                            {
                                //确定type为类并且继承自(实现)BaseDevProtocol
                                if (extype.IsClass && typeof(BaseDevProtocol).IsAssignableFrom(extype))
                                {
                                    BaseDevProtocol baseDevProtocol = (BaseDevProtocol)Activator.CreateInstance(extype);
                                    List<Operation> operations = Global.DataAccess.GetOperations(device.DeviceTypeId);
                                    List<DataItem> dataItems = Global.DataAccess.GetDataItems(device.Id);
                                    dataItems = baseDevProtocol.DeSerializeDataItems(dataItems);
                                    baseDevProtocol.Initialize(this,device, operations, dataItems);
                                    protocols.Add(device.Id, baseDevProtocol);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {
                _log.Error("协议加载出错:" + e.Message);
            }
        }
        public virtual void RaiseMessageEvent(RxTxCommand cmd)
        {
            // 判断是否要调用
           if(!Global.DataAccess.ShowMessage(cmd.ChannelId, cmd.DeviceId))
            {
                return;
            }
            if (cmd != null && OnNewMessage != null)
            {
                try
                {
                    OnNewMessage(new  RxTxCommand(cmd),EventArgs.Empty);
                }
                catch 
                {
                }
            }
        }
        protected Dictionary<string,List<string>> ExportMethods { get;} = new Dictionary<string, List<string>>();
        protected bool IsInitMethod { get; set; }
       

        public Channel ChlInfo { get; set; }
        public virtual bool Connected { get; protected set; }
        public virtual  bool Running { get; set; }
        public abstract bool Start();
        public virtual void Stop()
        {
            try
            {
                foreach (KeyValuePair<string, BaseDevProtocol> devProtocol in protocols)
                {
                    devProtocol.Value.Dev.IsConnected = false;
                    devProtocol.Value.DataItems.ForEach(sss=>sss.CurValue=0);
                }
            }
            catch 
            {
              
            }
           
        }

        protected virtual void NextDevice()
        {
            try
            {
                if (protocols.Count == 0)
                    return ;
                if (protocols.Count == 1)
                {
                    CurDevProtocol = protocols.Values.First();
                    return;
                }
               
                bool bfind = false;
                int count = protocols.Count, index=0;
                if (CurDevProtocol == null)
                {
                    foreach (BaseDevProtocol protocol in protocols.Values)
                    {
                        if (protocol.DataItems.Count > 0 && protocol.Dev.IsWork)
                        {
                            CurDevProtocol = protocol;
                            return;
                        }
                    }  
                }
                foreach (KeyValuePair<string, BaseDevProtocol> keyValuePair in protocols)
                {
                    if (bfind)
                    {
                        bfind = false;
                        if (keyValuePair.Value.DataItems.Count > 0 && keyValuePair.Value.Dev.IsWork)
                        {
                            CurDevProtocol = keyValuePair.Value;
                            return;
                        }
                    }
                    if (keyValuePair.Value.Equals(CurDevProtocol))
                    {
                        bfind = true;
                    }
                    index++;
                }
                if (count == index)
                {
                    var item = protocols.Values.First();
                    if (item.DataItems.Count > 0 && item.Dev.IsWork) CurDevProtocol = item;
                }
            }
            catch
            {
            }
        }
        protected abstract bool Connect(bool log = false);
        public abstract void PutCommand(RxTxCommand cmd);
        public abstract void PutInsertCommand(RxTxCommand cmd);
        public abstract RxTxCommand PostToExcute(string devId, string operId);
        public abstract RxTxCommand PostToExcute(string devId, string operId, string[] paras);
        public virtual RxTxCommand RemoteControl(string devId, string rcId, bool on)
        {
            if (protocols.ContainsKey(devId))
            {
                RxTxCommand cmd =   protocols[devId].RemoteControl(rcId, on);
                if (cmd != null)
                {
                    cmd.Name = "遥控报文";
                    PutCommand(cmd);
                    return cmd;
                }
            }
            return null;
        }
        /// <summary>
        /// 导出的方法
        /// </summary>
        /// <returns></returns>
        public  Dictionary<string,List<string>> GetExportMethods()
        {
            if (IsInitMethod)
                return ExportMethods;
            Type t = this.GetType();
            foreach (MethodInfo method in t.GetMethods())
            {
                var sss = method.GetCustomAttributes(typeof(ExportAttribute), false).OfType<ExportAttribute>();
                IEnumerable<ExportAttribute> attributes = sss as ExportAttribute[] ?? sss.ToArray();
                if (attributes.Any())
                {
                    List<string> des = new List<string>();
                    des.Add(attributes.First().Description);
                    // 返回值类型 参数类型
                    StringBuilder stringBuilder = new StringBuilder();
                    stringBuilder.Append(method.ReturnType.Name+",");
                    foreach (ParameterInfo parameter in method.GetParameters())
                    {
                        stringBuilder.Append(parameter.Name+":"+parameter.ParameterType.Name + " ");
                    }
                    des.Add(stringBuilder.ToString());
                    ExportMethods.Add(method.Name, des);
                }
            }
            IsInitMethod = true;
            return ExportMethods;
        }
        /// <summary>
        /// 获取方法的返回值类型和参数类型
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public string GetMethodParas(string method)
        {
            if (!IsInitMethod)
            {
                GetExportMethods();
            }
            if (ExportMethods.ContainsKey(method))
            {
                return ExportMethods[method][1];
            }
            return "";
        }
        /// <summary>
        /// 调用导出的方法
        /// </summary>
        /// <param name="method"></param>
        /// <param name="paras"></param>
        /// <returns></returns>
        public  object InvokeMethod(string method, string paras)
        {
            string[] parameters = null;
            if (!string.IsNullOrEmpty(paras))
            {
                parameters = paras.Split('|');
            }
            Type t = this.GetType();
            MethodInfo m = t.GetMethod(method);
            if (m == null)
            {
                throw new Exception("没有找到指定方法!");
            }
            List<object> paraObjects = new List<object>();
            if (parameters != null && parameters.Length > 0)
            {
                int index = 0;
                foreach (ParameterInfo parameterInfo in m.GetParameters())
                {
                    paraObjects.Add(GetObject(parameterInfo.ParameterType.Name, parameters[index]));
                    index++;
                }
            }
            return t.GetMethod(method)?.Invoke(this, paraObjects.ToArray());
        }
        /// <summary>
        /// 字符串转指定类型的对象(值)
        /// </summary>
        /// <param name="typeName"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        private object GetObject(string typeName, string value)
        {
            switch (typeName.ToLower())
            {
                case "int16":
                    return Convert.ToInt16(value);
                case "int32":
                    return Convert.ToInt32(value);
                case "int64":
                    return Convert.ToInt64(value);
                case "string":
                    return Convert.ToString(value);
                case "datetime":
                    return Convert.ToDateTime(value);
                case "boolean":
                    return Convert.ToBoolean(value);
                case "char":
                    return Convert.ToChar(value);
                case "double":
                    return Convert.ToDouble(value);
                case "list`1":
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<List<Int32>>(value);
                default:
                    return value;
            }
        }
        /// <summary>
        /// 获取设备驱动
        /// </summary>
        /// <param name="device"></param>
        /// <returns></returns>
        public BaseDevProtocol GetDevProtocolByDevice(Device device)
        {
            if (device == null)
                return null;
            foreach (KeyValuePair<string, BaseDevProtocol> pair in protocols)
            {
                if (pair.Key == device.Id)
                {
                    return pair.Value;
                }
            }
            return null;
        }
        public Device GetDeviceById(string devId)
        {
            if (string.IsNullOrEmpty(devId))
                return null;
            foreach (KeyValuePair<string, BaseDevProtocol> pair in protocols)
            {
                if (pair.Key == devId)
                {
                    return pair.Value.Dev;
                }
            }
            return null;
        }
        /// <summary>
        /// 根据设备Id获取设备驱动
        /// </summary>
        /// <param name="devId"></param>
        /// <returns></returns>
        public BaseDevProtocol GetDevProtocolByDevice(string devId)
        {
            foreach (KeyValuePair<string, BaseDevProtocol> pair in protocols)
            {
                if (pair.Key == devId)
                {
                    return pair.Value;
                }
            }
            return null;
        }
        /// <summary>
        /// 获取通道内所有数据项
        /// </summary>
        /// <returns></returns>
        public List<DataItem> GetChlDataItems()
        {
            List < DataItem > dataItems = new List<DataItem>();
            foreach (KeyValuePair<string, BaseDevProtocol> pair in protocols)
            {
                if (pair.Value.DataItems.Count > 0)
                {
                    dataItems.AddRange(pair.Value.DataItems);
                }
            }
            return dataItems;
        }
        /// <summary>
        /// 获取需要存储的数据项
        /// </summary>
        /// <returns></returns>
        public List<DataItem> GetStoreDataItems()
        {
            List<DataItem> dataItems = new List<DataItem>();
            foreach (KeyValuePair<string, BaseDevProtocol> pair in protocols)
            {
                if (pair.Value.DataItems.Count > 0)
                {
                    var items = pair.Value.DataItems.FindAll(sss => sss.IsStorage);
                    if (items.Count > 0)
                    {
                        dataItems.AddRange(items);
                    }
                }
            }
            return dataItems;
        }
       
        #endregion

    }
}
